/**

***  Copyright (c) 2004-2007, Masaki OSHITA (www.oshita-lab.org)
**/


#include "stdafx.h"
#ifndef  _BVH_H_
#define  _BVH_H_


#include <vector>
#include <map>
#include <string>


#define INDENT for ( int j = 0; j < layer; j++) file << "\t"
#define BEGIN_BRACKET file << "{"
#define CLOSE_BRACKET file << "}"
#define NEXT_LINE file << "\n"
#define OFFSET file << "OFFSET"
#define HIERARCHY file << "HIERARCHY"
#define ROOT file << "ROOT "
#define JOINT file << "JOINT "
#define JOINT_NAME file << joint->name
#define JOINT_OFFSET for ( int j = 0; j < 3; j++) file << "\t" << setiosflags(ios::fixed) << setprecision(6) << joint->offset[j]
#define CHANNELS file << "CHANNELS\t" << joint->channels.size()
#define END_SITE file << "End Site"
#define SITES for ( int j = 0; j < 3; j++) file << "\t" << joint->site[j]
#define MOTION file << "MOTION"
#define FRAMES file << "Frames: " << GetNumFrame()
#define FRAME_TIME file << "Frame Time: "  << GetInterval()
#define MOTION_DATA file << setiosflags(ios::fixed) << setprecision(2) << GetMotion(i, j) << "\t"


using namespace  std;

class  BVH
{
public:
	enum  ChannelEnum
	{
		X_ROTATION, Y_ROTATION, Z_ROTATION,
		X_POSITION, Y_POSITION, Z_POSITION
	};
	struct  Joint;

	struct  Channel
	{
		Joint *				joint;
		ChannelEnum		type;
		int						index;
	};

	struct  Joint
	{
		string							name;
		int								index;
		Joint *						parent;
		vector< Joint * >			children;
		Ogre::Vector3				offset;
		bool							has_site;
		double						site[3];
		vector< Channel * >	channels;
	};

private:	// class members
	int			bvhNo;
	bool		is_load_success;
	bool		is_save_success;
	string		file_name;  
	string		save_file_name;  
	string		motion_name; 
	int			num_channel;
	vector< Channel * >	channels;
	vector< Joint * >			joints;
	map< string, Joint * >	joint_index;
	int			num_frame;  
	double	interval;   
	double*	motion;

public:	// public class members
	Ogre::Vector3 BVH_pos;
	bool pathCalculated;
	std::vector<Ogre::Vector3> ctlPnt;

public:	// basic methods
	BVH();
	BVH( const char * bvh_file_name );
	~BVH();
	void  Clear();
	void  Load( const char * bvh_file_name );
	void  Save( const char * bvh_file_name );
	void  AddJoint( ofstream &file, const Joint *joint );

public:	// Gets...
	bool  IsLoadSuccess() const { return is_load_success; }
	const string &		GetFileName() const { return file_name; }
	const string &		GetMotionName() const { return motion_name; }
	const int			GetNumJoint() const { return  joints.size(); }
	const Joint*		GetJoint( int no ) const { return  joints[no]; }
	const int			GetNumChannel() const { return  channels.size(); }
	const Channel*	GetChannel( int no ) const { return  channels[no]; }
	const Joint* GetJoint( const string & j ) const
	{
		map< string, Joint * >::const_iterator  i = joint_index.find( j );
		return  ( i != joint_index.end() ) ? (*i).second : NULL;
	}
	const Joint* GetJoint( const char * j ) const
	{
		map< string, Joint * >::const_iterator  i = joint_index.find( j );
		return  ( i != joint_index.end() ) ? (*i).second : NULL;
	}
	int			GetBvhNo() const { return  bvhNo; }
	int			GetNumFrame() const { return  num_frame; }
	double	GetInterval() const { return  interval; }
	double	GetMotion( int f, int c ) const { return  motion[ f*num_channel + c ]; }
	void		SetBvhNo(const int no) { bvhNo = no; }
	void		SetMotion( int f, int c, double v ) { motion[ f*num_channel + c ] = v; }



	// Sets... (For saving bvh)
	bool  IsSaveSuccess() const { return is_save_success; }
	void	SetFileName(const char * bvh_file_name) { save_file_name = bvh_file_name; }
	
};

#endif // _BVH_H_
